package client;

import database.BeePool;
import tools.FileoutputUtil;
import tools.MaplePacketCreator;

import java.io.Serializable;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.*;
import java.util.Map.Entry;

public class BuddyList implements Serializable {
    public static String DEFAULT_GROUP = "其他";
    private Map<Integer, BuddyEntry> buddies;
    private byte capacity;
    private Deque<BuddyEntry> pendingReqs;

    public BuddyList(byte capacity) {
        this.pendingReqs = (Deque<BuddyEntry>) new LinkedList();
        this.buddies = (Map<Integer, BuddyEntry>) new LinkedHashMap();
        this.capacity = capacity;
    }

    public BuddyList(int capacity) {
        this.pendingReqs = (Deque<BuddyEntry>) new LinkedList();
        this.buddies = (Map<Integer, BuddyEntry>) new LinkedHashMap();
        this.capacity = (byte) capacity;
    }

    public boolean contains(int characterId) {
        return this.buddies.containsKey(Integer.valueOf(characterId));
    }

    public boolean containsVisible(int charId) {
        BuddyEntry ble = (BuddyEntry) this.buddies.get(Integer.valueOf(charId));
        return ble != null && ble.isVisible();
    }

    public byte getCapacity() {
        return this.capacity;
    }

    public void setCapacity(byte newCapacity) {
        this.capacity = newCapacity;
    }

    public BuddyEntry get(int characterId) {
        return (BuddyEntry) this.buddies.get(Integer.valueOf(characterId));
    }

    public BuddyEntry get(String characterName) {
        String searchName = characterName.toLowerCase();
        for (BuddyEntry ble : this.buddies.values()) {
            if (ble.getName().toLowerCase().equals(searchName)) {
                return ble;
            }
        }
        return null;
    }

    public void put(BuddyEntry newEntry) {
        this.buddies.put(Integer.valueOf(newEntry.getCharacterId()), newEntry);
    }

    public void remove(int characterId) {
        this.buddies.remove(Integer.valueOf(characterId));
    }

    public Collection<BuddyEntry> getBuddies() {
        return this.buddies.values();
    }

    public boolean isFull() {
        return this.buddies.size() >= this.capacity;
    }

    public Collection<Integer> getBuddiesIds() {
        return this.buddies.keySet();
    }

    public void loadFromTransfer(Map<BuddyEntry, Boolean> data) {
        for (Entry<BuddyEntry, Boolean> qs : data.entrySet()) {
            BuddyEntry buddyid = (BuddyEntry) qs.getKey();
            boolean pair = ((Boolean) qs.getValue()).booleanValue();
            if (!pair) {
                this.pendingReqs.push(buddyid);
            } else {
                this.put(new BuddyEntry(buddyid.getName(), buddyid.getCharacterId(), buddyid.getGroup(), -1, true, buddyid.getLevel(), buddyid.getJob()));
            }
        }
    }

    public void loadFromDb(int characterId) throws SQLException {
        PreparedStatement ps = null;
        ResultSet rs = null;
        try (Connection con = BeePool.getConnection()) {
            ps = con.prepareStatement("SELECT b.buddyid, b.pending, c.name as buddyname, c.job as buddyjob, c.level as buddylevel, b.groupname FROM buddies as b, characters as c WHERE c.id = b.buddyid AND b.characterid = ?");
            ps.setInt(1, characterId);
            rs = ps.executeQuery();
            while (rs.next()) {
                int buddyid = rs.getInt("buddyid");
                String buddyname = rs.getString("buddyname");
                if (rs.getInt("pending") == 1) {
                    this.pendingReqs.push(new BuddyEntry(buddyname, buddyid, rs.getString("groupname"), -1, false, rs.getInt("buddylevel"), rs.getInt("buddyjob")));
                } else {
                    this.put(new BuddyEntry(buddyname, buddyid, rs.getString("groupname"), -1, true, rs.getInt("buddylevel"), rs.getInt("buddyjob")));
                }
            }
            rs.close();
            ps.close();
            ps = con.prepareStatement("DELETE FROM buddies WHERE pending = 1 AND characterid = ?");
            ps.setInt(1, characterId);
            ps.executeUpdate();
            ps.close();
            
        } catch (SQLException ex) {
            FileoutputUtil.outError("logs/资料库异常.txt", (Throwable) ex);
        }

    }

    public BuddyEntry pollPendingRequest() {
        return (BuddyEntry) this.pendingReqs.pollLast();
    }

    public void addBuddyRequest(MapleClient client, int buddyId, String buddyName, int buddyChannel, int buddyLevel, int buddyJob) {
        this.put(new BuddyEntry(buddyName, buddyId, "其他", buddyChannel, false, buddyLevel, buddyJob));
        if (this.pendingReqs.isEmpty()) {
            client.sendPacket(MaplePacketCreator.requestBuddylistAdd(buddyId, buddyName, buddyLevel, buddyJob));
        } else {
            BuddyEntry newPair = new BuddyEntry(buddyName, buddyId, "其他", -1, false, buddyJob, buddyLevel);
            this.pendingReqs.push(newPair);
        }
    }

    public static int getBuddyCount(int chrId, int pending) {
        int count = 0;
        PreparedStatement ps = null;
        ResultSet rs = null;
        try (Connection con = BeePool.getConnection()) {
            ps = con.prepareStatement("SELECT COUNT(*) as buddyCount FROM buddies WHERE characterid = ? AND pending = ?");
            ps.setInt(1, chrId);
            ps.setInt(2, pending);
            rs = ps.executeQuery();
            if (!rs.next()) {
                rs.close();
                ps.close();
                
                throw new RuntimeException("BuddyListHandler: getBuudyCount From DB is Error.");
            }
            count = rs.getInt("buddyCount");
            rs.close();
            ps.close();
            
        } catch (SQLException ex) {
            ex.printStackTrace();
            FileoutputUtil.outError("logs/资料库异常.txt", (Throwable) ex);
        }

        return count;
    }

    public static int getBuddyCapacity(int charId) {
        int capacity = -1;
        PreparedStatement ps = null;
        ResultSet rs = null;
        try (Connection con = BeePool.getConnection()) {
            ps = con.prepareStatement("SELECT buddyCapacity FROM characters WHERE id = ?");
            ps.setInt(1, charId);
            rs = ps.executeQuery();
            if (rs.next()) {
                capacity = rs.getInt("buddyCapacity");
            }
            rs.close();
            ps.close();
            
        } catch (SQLException ex) {
            ex.printStackTrace();
            FileoutputUtil.outError("logs/资料库异常.txt", (Throwable) ex);
        }

        return capacity;
    }

    public static int getBuddyPending(int chrId, int buddyId) {
        int pending = -1;
        PreparedStatement ps = null;
        ResultSet rs = null;
        try (Connection con = BeePool.getConnection()) {
            ps = con.prepareStatement("SELECT pending FROM buddies WHERE characterid = ? AND buddyid = ?");
            ps.setInt(1, chrId);
            ps.setInt(2, buddyId);
            rs = ps.executeQuery();
            if (rs.next()) {
                pending = rs.getInt("pending");
            }
            rs.close();
            ps.close();
            
        } catch (SQLException ex) {
            ex.printStackTrace();
            FileoutputUtil.outError("logs/资料库异常.txt", (Throwable) ex);
        }

        return pending;
    }

    public static void addBuddyToDB(MapleCharacter player, BuddyEntry buddy) {
        PreparedStatement ps = null;
        ResultSet rs = null;
        try (Connection con = BeePool.getConnection()) {
            ps = con.prepareStatement("INSERT INTO buddies (`characterid`, `buddyid`, `groupname`, `pending`) VALUES (?, ?, ?, 1)");
            ps.setInt(1, buddy.getCharacterId());
            ps.setInt(2, player.getId());
            ps.setString(3, buddy.getGroup());
            ps.executeUpdate();
            ps.close();
            
        } catch (SQLException ex) {
            ex.printStackTrace();
            FileoutputUtil.outError("logs/资料库异常.txt", (Throwable) ex);
        }

    }

    public enum BuddyOperation {
        ADDED,
        DELETED;
    }

    public enum BuddyAddResult {
        BUDDYLIST_FULL,
        ALREADY_ON_LIST,
        OK;
    }
}
